package org.example.batch;

import org.example.domain.Student;
import org.springframework.batch.item.ItemProcessor;

/**
 * 大数据量学生批处理器 - 教学版本
 * 
 * 这个处理器专门用于演示大数据量场景下的批处理最佳实践
 * 
 * 大数据量处理的关键考虑因素：
 * 1. 内存使用：避免一次性加载所有数据到内存
 * 2. 处理性能：优化处理逻辑，减少每条记录的处理时间
 * 3. 数据库连接：合理使用数据库连接，避免连接池耗尽
 * 4. 事务管理：合理设置chunk大小，平衡性能和事务安全
 * 5. 错误处理：在大数据量场景下的容错和重试策略
 * 6. 监控统计：实时监控处理进度和性能指标
 * 
 * 性能优化技巧：
 * - 减少不必要的对象创建
 * - 避免复杂的字符串操作
 * - 缓存重复使用的数据
 * - 批量操作外部资源
 * 
 * 适用场景：
 * - 数据库中有百万级别的学生记录
 * - 需要对所有学生进行统一的数据处理
 * - 定期的数据清洗和标准化任务
 * - 数据迁移和转换任务
 * 
 * @author example
 */
public class BigDataStudentProcessor implements ItemProcessor<Student, Student> {
    
    // 统计信息 - 实际应用中可以使用更专业的监控工具
    private static long totalProcessed = 0;
    private static long adultCount = 0;
    private static long minorCount = 0;
    private static long invalidDataCount = 0;
    private static long startTime = 0;
    
    /**
     * 重置统计信息 - 每次Job开始时调用
     */
    public static void resetStatistics() {
        totalProcessed = 0;
        adultCount = 0;
        minorCount = 0;
        invalidDataCount = 0;
        startTime = System.currentTimeMillis();
        System.out.println("=== 大数据量处理统计信息已重置 ===");
    }
    
    /**
     * 获取当前统计信息
     */
    public static void printStatistics() {
        long elapsed = System.currentTimeMillis() - startTime;
        double recordsPerSecond = totalProcessed > 0 ? (totalProcessed * 1000.0 / elapsed) : 0;
        
        System.out.println("\n=== 大数据量处理统计信息 ===");
        System.out.println("总处理记录数: " + totalProcessed);
        System.out.println("成年学生数: " + adultCount);
        System.out.println("未成年学生数: " + minorCount);
        System.out.println("无效数据数: " + invalidDataCount);
        System.out.println("处理耗时: " + elapsed + " ms");
        System.out.println("处理速度: " + String.format("%.2f", recordsPerSecond) + " 记录/秒");
        System.out.println("================================\n");
    }

    /**
     * 处理单个学生记录
     * 
     * 大数据量处理的核心原则：
     * 1. 快速处理：每条记录的处理时间要尽可能短
     * 2. 内存友好：不保存不必要的状态信息
     * 3. 异常安全：合理处理异常，避免影响整个批处理
     * 4. 统计监控：记录关键的处理统计信息
     * 
     * @param student 从数据库读取的学生对象
     * @return 处理后的学生对象，null表示过滤该记录
     * @throws Exception 处理异常
     */
    @Override
    public Student process(Student student) throws Exception {
        // 增加处理计数
        totalProcessed++;
        
        // 每处理1000条记录输出一次进度信息
        if (totalProcessed % 1000 == 0) {
            System.out.println("已处理 " + totalProcessed + " 条学生记录...");
        }
        
        try {
            // 数据验证 - 在大数据量场景下，数据质量问题更常见
            if (student == null) {
                invalidDataCount++;
                System.out.println("警告：遇到null学生记录，跳过处理");
                return null;
            }
            
            if (student.getName() == null || student.getName().trim().isEmpty()) {
                invalidDataCount++;
                System.out.println("警告：学生ID " + student.getId() + " 姓名为空，跳过处理");
                return null;
            }
            
            // 数据清洗和标准化
            String cleanName = cleanStudentName(student.getName());
            student.setName(cleanName);
            
            // 年龄处理和分类
            Integer age = student.getAge();
            if (age == null || age < 0 || age > 150) {
                // 对于年龄异常的数据，可以选择设置默认值或跳过
                System.out.println("警告：学生 " + student.getName() + " 年龄异常: " + age + "，设置为默认值");
                age = 20; // 设置默认年龄
                student.setAge(age);
                invalidDataCount++;
            }
            
            // 业务逻辑处理 - 根据年龄进行分类标记
            String ageCategory = getAgeCategory(age);
            String processedName = "[" + ageCategory + "]" + cleanName;
            student.setName(processedName);
            
            // 统计分类信息
            if (age >= 18) {
                adultCount++;
            } else {
                minorCount++;
            }
            
            // 性别数据标准化
            standardizeGender(student);
            
            // 邮箱验证和标准化
            standardizeEmail(student);
            
            // 在实际应用中，这里还可能包括：
            // - 调用外部API获取补充信息
            // - 数据库查询关联信息
            // - 复杂的业务规则计算
            // - 数据加密或脱敏处理
            
            return student;
            
        } catch (Exception e) {
            // 在大数据量处理中，个别记录的处理失败不应该影响整个批处理
            invalidDataCount++;
            System.err.println("处理学生记录失败 ID: " + student.getId() + 
                             ", 姓名: " + student.getName() + 
                             ", 错误: " + e.getMessage());
            
            // 可以选择跳过该记录或者抛出异常
            // 跳过记录：return null;
            // 抛出异常：throw e;
            // 这里选择跳过，以保证批处理的稳定性
            return null;
        }
    }
    
    /**
     * 清洗学生姓名
     * 大数据处理中，数据清洗是非常重要的环节
     */
    private String cleanStudentName(String name) {
        if (name == null) return null;
        
        // 去除前后空格
        name = name.trim();
        
        // 去除多余的空格
        name = name.replaceAll("\\s+", " ");
        
        // 去除特殊字符（根据业务需求定制）
        name = name.replaceAll("[^\\u4e00-\\u9fa5a-zA-Z\\s]", "");
        
        return name;
    }
    
    /**
     * 获取年龄分类
     * 优化版本：使用简单的if-else而不是复杂的逻辑，提高处理速度
     */
    private String getAgeCategory(Integer age) {
        if (age == null) return "未知";
        if (age < 18) return "未成年";
        if (age <= 25) return "青年";
        if (age <= 35) return "青壮年";
        if (age <= 60) return "中年";
        return "老年";
    }
    
    /**
     * 性别数据标准化
     * 处理各种可能的性别表示方式
     */
    private void standardizeGender(Student student) {
        String gender = student.getGender();
        if (gender == null) {
            student.setGender("U"); // Unknown
            return;
        }
        
        gender = gender.trim().toUpperCase();
        switch (gender) {
            case "M":
            case "MALE":
            case "男":
                student.setGender("M");
                break;
            case "F":
            case "FEMALE":
            case "女":
                student.setGender("F");
                break;
            default:
                student.setGender("U"); // Unknown
        }
    }
    
    /**
     * 邮箱标准化
     * 简单的邮箱格式验证和标准化
     */
    private void standardizeEmail(Student student) {
        String email = student.getEmail();
        if (email == null || email.trim().isEmpty()) {
            return;
        }
        
        email = email.trim().toLowerCase();
        
        // 简单的邮箱格式验证
        if (!email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) {
            // 邮箱格式不正确，可以选择清空或保持原值
            System.out.println("警告：学生 " + student.getName() + " 邮箱格式不正确: " + email);
            student.setEmail(null);
        } else {
            student.setEmail(email);
        }
    }
} 